#include "dev_api.h"
#include "com_device.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define COM_RECV_CACHE_SIZE UART_CACHE_SIZE
#define COM_SEND_CACHE_SIZE 512
com_dev_t *com_list_head = NULL;
rt_sem_t com_dev_sem = NULL;
#ifdef USING_UART1
#define COM_UART1
#endif
#ifdef USING_UART2
#ifndef USING_SHELL
#define COM_UART2
#endif
#endif
#ifdef USING_UART3
#define COM_UART3
#endif

#ifdef COM_UART1
void com_uart1_init(void);
#endif
#ifdef COM_UART2
void com_uart2_init(void);
#endif
#ifdef COM_UART3
void com_uart3_init(void);
#endif

int com_device_init(void)
{
#ifdef COM_UART1
  com_uart1_init();
#endif
#ifdef COM_UART2
  com_uart2_init();
#endif
#ifdef COM_UART3
  com_uart3_init();
#endif
  com_dev_sem = rt_sem_create("com_dev", 0, RT_IPC_FLAG_FIFO);
  if(com_dev_sem == NULL) {
    printf("error: create com device semaphore failed.\n");
    return -1;
  }
  return 0;
}
INIT_APP_EXPORT(com_device_init);

void com_insert_list(com_dev_t *p_com)
{
  com_dev_t *com_list;
  if(com_list_head == NULL) {
    com_list_head = p_com;
  }
  else {
    com_list = com_list_head;
    while(com_list->next != NULL) {
      com_list = com_list->next;
    }
    com_list->next = p_com;
  }
}

void com_irq_register(com_dev_t *p_com, int (*callback_entry)(void*))
{
  p_com->irq_callback = callback_entry;
}

void uart_recv_callback(UART_HandleTypeDef *huart, unsigned char* pbuf, int size)
{
  com_dev_t *p_com = NULL;
#ifdef COM_UART1
  if(huart == &huart1) p_com = &dev_uart1;
#endif
#ifdef COM_UART2
  if(huart == &huart2) p_com = &dev_uart2;
#endif
#ifdef COM_UART3
  if(huart == &huart3) p_com = &dev_uart3;
#endif
  if(!p_com) return;
  if(p_com->recv_buf == NULL) return;
  p_com->timestamp = HAL_GetTick();
  p_com->recv_size = size;
  memcpy(p_com->recv_buf, pbuf, size);
  if(p_com->irq_callback != NULL) p_com->irq_callback(p_com);
  printf("COM: %s\n", p_com->name);
  printf("recv size: %d bytes\n", p_com->recv_size);
  print_buffer(p_com->recv_buf, p_com->recv_size);
  rt_sem_release(com_dev_sem);
}
#ifdef COM_UART1
com_dev_t dev_uart1;
unsigned char recv_cache1[COM_RECV_CACHE_SIZE];
unsigned char send_cache1[COM_SEND_CACHE_SIZE];

int uart1_write(void *pbuf, int size)
{
  if(size > COM_SEND_CACHE_SIZE) return 0;
  printf("COM: %s\n", dev_uart1.name);
  printf("send size: %d bytes\n", size);
  print_buffer(pbuf, size);
  dev_uart1.send_size = size;
  memcpy(dev_uart1.send_buf, pbuf, size);
  return uart_write(&huart1, dev_uart1.send_buf, dev_uart1.send_size);
}

int uart1_read(void *pbuf, int size)
{
  static uint32_t cur_timestamp;
  if(memcmp(&cur_timestamp, &dev_uart1.timestamp, 4)) {
    if(size < dev_uart1.recv_size) return 0;
    memcpy(&cur_timestamp, &dev_uart1.timestamp, 4);
    memcpy(pbuf, dev_uart1.recv_buf, dev_uart1.recv_size);
    return dev_uart1.recv_size;
  }
  return 0;
}

void com_uart1_init(void)
{
  memset(&dev_uart1, 0, sizeof(com_dev_t));
  sprintf(dev_uart1.name, "USART1");
  dev_uart1.recv_size = 0;
  dev_uart1.recv_buf = recv_cache1;
  dev_uart1.send_size = 0;
  dev_uart1.send_buf = send_cache1;
  dev_uart1.write = uart1_write;
  dev_uart1.read = uart1_read;
  dev_uart1.irq_callback = NULL;
  dev_uart1.next = NULL;
  com_insert_list(&dev_uart1);
}
#endif
#ifdef COM_UART2
com_dev_t dev_uart2;
unsigned char recv_cache2[COM_RECV_CACHE_SIZE];
unsigned char send_cache2[COM_SEND_CACHE_SIZE];

int uart2_write(void *pbuf, int size)
{
  if(size > COM_SEND_CACHE_SIZE) return 0;
  printf("COM: %s\n", dev_uart2.name);
  printf("send size: %d bytes\n", size);
  print_buffer(pbuf, size);
  dev_uart2.send_size = size;
  memcpy(dev_uart2.send_buf, pbuf, size);
  return uart_write(&huart2, dev_uart2.send_buf, dev_uart2.send_size);
}

int uart2_read(void *pbuf, int size)
{
  static uint32_t cur_timestamp;
  if(memcmp(&cur_timestamp, &dev_uart2.timestamp, 4)) {
    if(size < dev_uart2.recv_size) return 0;
    memcpy(&cur_timestamp, &dev_uart2.timestamp, 4);
    memcpy(pbuf, dev_uart2.recv_buf, dev_uart2.recv_size);
    return dev_uart2.recv_size;
  }
  return 0;
}

void com_uart2_init(void)
{
  memset(&dev_uart2, 0, sizeof(com_dev_t));
  sprintf(dev_uart2.name, "USART2");
  dev_uart2.recv_size = 0;
  dev_uart2.recv_buf = recv_cache2;
  dev_uart2.send_size = 0;
  dev_uart2.send_buf = send_cache2;
  dev_uart2.write = uart2_write;
  dev_uart2.read = uart2_read;
  dev_uart2.irq_callback = NULL;
  dev_uart2.next = NULL;
  com_insert_list(&dev_uart2);
}
#endif
#ifdef COM_UART3
com_dev_t dev_uart3;
unsigned char recv_cache3[COM_RECV_CACHE_SIZE];
unsigned char send_cache3[COM_SEND_CACHE_SIZE];

int uart3_write(void *pbuf, int size)
{
  if(size > COM_SEND_CACHE_SIZE) return 0;
  printf("COM: %s\n", dev_uart3.name);
  printf("send size: %d bytes\n", size);
  print_buffer(pbuf, size);
  dev_uart3.send_size = size;
  memcpy(dev_uart3.send_buf, pbuf, size);
  return uart_write(&huart3, dev_uart3.send_buf, dev_uart3.send_size);
}

int uart3_read(void *pbuf, int size)
{
  static uint32_t cur_timestamp;
  if(memcmp(&cur_timestamp, &dev_uart3.timestamp, 4)) {
    if(size < dev_uart3.recv_size) return 0;
    memcpy(&cur_timestamp, &dev_uart3.timestamp, 4);
    memcpy(pbuf, dev_uart3.recv_buf, dev_uart3.recv_size);
    return dev_uart3.recv_size;
  }
  return 0;
}

void com_uart3_init(void)
{
  memset(&dev_uart3, 0, sizeof(com_dev_t));
  sprintf(dev_uart3.name, "USART3");
  dev_uart3.recv_size = 0;
  dev_uart3.recv_buf = recv_cache3;
  dev_uart3.send_size = 0;
  dev_uart3.send_buf = send_cache3;
  dev_uart3.write = uart3_write;
  dev_uart3.read = uart3_read;
  dev_uart3.irq_callback = NULL;
  dev_uart3.next = NULL;
  com_insert_list(&dev_uart3);
}
#endif
